package game;


import globals.GlobalObjects;
import graphics.GraphicalObject;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.swing.Timer;

import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

import shader.WaveShader;

import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureCoords;
import com.sun.opengl.util.texture.TextureIO;




public class Main implements GLEventListener
{

	GLAutoDrawable drawable;
	String textPath = "Resources/game.txt";
	String menuPath = "Resources/bunny_menu2.jpg";
	String lastScreenPath = "Resources/dead_robot.jpg";
	String introPath = "Resources/intro.jpg";
	String gOverPath = "Resources/gameOver.jpg";
	String lives0Path = "Resources/lives/empty.jpg";
	String lives1Path = "Resources/lives/one.jpg";
	String lives2Path = "Resources/lives/two.jpg";
	String lives3Path = "Resources/lives/three.jpg";
	String lives4Path = "Resources/lives/four.jpg";
	String lives5Path = "Resources/lives/five.jpg";
	String weapon1Path = "Resources/grenade.jpg";
	String weapon2Path = "Resources/missile.jpg";
	File fmenu  = new File(menuPath);
	File fintro = new File(introPath);
	Game game;
	static GLCanvas canvas;
	Composite composite;
	Timer paintTimer;
	int repaintFrequence=40;
	private boolean showMenu = true;
	private boolean showIntro = false;
	private boolean showGameOver = false;
	
	Texture menu;
	Texture intro;
	Texture gameOver;
	Texture empty;
	Texture lastScreen;
	Texture lives1;
	Texture lives2;
	Texture lives3;
	Texture lives4;
	Texture lives5;

	Texture weapon1;
	Texture weapon2;
	
	TextLayer tl;
	Texture text;
	String mission;
	Color c = Color.GREEN;
    int fontsize = 16;
	Font font = new Font ("Garamond", 0 , fontsize);
	
	boolean gameIsOn = false;
	
	public static void main(String[] args) 
	{
		Display display = new Display();
		
		Main main = new Main();
		main.runMain(display);
		display.dispose();
		System.exit(0);
	}
	
	void runMain(Display display)
	{
                
		game = initializeGame();

		final Shell shell = new Shell(display);
		shell.setText("The Carrot Quest");
		GridLayout gridLayout = new GridLayout();
		gridLayout.marginHeight = 0;
		gridLayout.marginWidth = 0;
	
		shell.setLayout(gridLayout);
		

		// this allows us to set particular properties for the GLCanvas
		GLCapabilities glCapabilities = new GLCapabilities();

		glCapabilities.setDoubleBuffered(true);
		glCapabilities.setHardwareAccelerated(true);
		// instantiate the canvas
		canvas = new GLCanvas(glCapabilities);
		

		// we can't use the default Composite because using the AWT bridge
		// requires that it have the property of SWT.EMBEDDED
		composite = new Composite(shell, SWT.EMBEDDED);
		GridData ld = new GridData(GridData.FILL_BOTH);
		composite.setLayoutData(ld);
		
		// the grid layout allows you to add more widgets in the main window.
		
		// set the internal layout so our canvas fills the whole control
		FillLayout clayout = new FillLayout();
		composite.setLayout(clayout);

		// create the special frame bridge to AWT
		final java.awt.Frame glFrame = SWT_AWT.new_Frame(composite);
		// we need the listener so we get the GL events
		canvas.addGLEventListener(this);

		// finally, add our canvas as a child of the frame
		glFrame.add(canvas);

		composite.setFocus();
		//	 canvas.requestFocus();
	
		composite.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent k) {
			
				switch (k.keyCode) {
				case 's':
					if (!gameIsOn){
						startGame();
						gameIsOn = true;
						showMenu = false;
					}
					break;
				case 'i':
					showIntro = true;		
					break;
				case 'q':
					System.exit(0);
				}
			}
		});
		
		composite.addKeyListener(game.getKeyAdapter());
		
		
		canvas.addMouseListener(
			new java.awt.event.MouseAdapter(){

				@Override
				public void mouseClicked(java.awt.event.MouseEvent e) {
					double x=e.getX();
					double y=e.getY();
					int drawWidth=canvas.getWidth();
					int drawHeight=canvas.getHeight();
					
					//PLAY
					if (showMenu && (x>0.75*drawWidth && x<0.95*drawWidth) &&
							        (y>0.375*drawHeight && y<0.53*drawHeight))
					{
						
						if (!gameIsOn){
							startGame();
							gameIsOn = true;
							showMenu = false;
						}
						

					//INTRO
					}else if (showMenu && (x>0.75*drawWidth && x<0.95*drawWidth) &&
						        (y>0.58*drawHeight && y<0.72*drawHeight)){
						
						showIntro = true;		
					//EXIT
					}else if (showMenu && !showIntro && (x>0.75*drawWidth && x<0.95*drawWidth) &&
					        	(y>0.80*drawHeight && y<0.94*drawHeight)){
						
						System.exit(0);
						
					//Back in intro	
					}else if (showIntro && (x>0.80*drawWidth && x<0.94*drawWidth) &&
				        	(y>0.75*drawHeight && y<0.84*drawHeight))
					{
						showIntro = false;
						showMenu = true;
					//
					}else if (showGameOver && (x>0.64*drawWidth && x<0.94*drawWidth) &&
				        	(y>0.73*drawHeight && y<0.93*drawHeight))
					{
							System.exit(0);					
					}
					
					
					canvas.repaint();
				}
		});
		
		canvas.addMouseMotionListener(
			new java.awt.event.MouseMotionAdapter(){
				@Override
				public void mouseDragged(MouseEvent e) {
					// TODO: Possible replace with something to do when the mouse is dragged in the window.
					//System.out.println("drag: " + e);	
				}
		});

		paintTimer = new Timer(repaintFrequence, new Painter(canvas, game));
		
		// show it all
		shell.open();
		
		while (!shell.isDisposed ()) {
			if (!display.readAndDispatch()) display.sleep();
		}
		
		
	}

	private void startGame() {
		paintTimer.start();
		game.start(repaintFrequence);
	}
	
	public Game initializeGame(){
		GlobalObjects.clearData();
		Universe.clearUniverseData();
		Game game = null;
		try{
			Parser p = new Parser(textPath);
			game = p.parse();
		}
		catch(Exception exp){
			System.out.println("ERROR: " + exp);
		}
		mission  = game.getCurrentMission();
		return game;
		
	}


	//@Override
	public void init(GLAutoDrawable drawable) 
	{
		this.drawable = drawable;
		try{
			menu = TextureIO.newTexture( fmenu, true);
			intro = TextureIO.newTexture( fintro, true);
			gameOver = TextureIO.newTexture( new File(gOverPath), true);
			lastScreen = TextureIO.newTexture( new File(lastScreenPath), true);
			empty = TextureIO.newTexture( new File(lives0Path), true);
			lives1 = TextureIO.newTexture(  new File(lives1Path), true);
			lives2 = TextureIO.newTexture(  new File(lives2Path), true);
			lives3 = TextureIO.newTexture(  new File(lives3Path), true);
			lives4 = TextureIO.newTexture(  new File(lives4Path), true);
			lives5 = TextureIO.newTexture(  new File(lives5Path), true);
			weapon1 = TextureIO.newTexture(  new File(weapon1Path), true);
			weapon2 = TextureIO.newTexture(  new File(weapon2Path), true);
		}catch (Exception e){
			System.out.println("ERROR");
			e.printStackTrace();
		}
	    GL gl = drawable.getGL();
		
	    try {
			WaveShader.init(gl);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	    System.out.println(gl.glGetString(GL.GL_EXTENSIONS));
	    System.out.println(gl.glGetString(GL.GL_VERSION));
	    gl.glShadeModel(GL.GL_SMOOTH);
	    gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	    gl.glClearDepth(1.0f);
	    gl.glEnable(GL.GL_DEPTH_TEST);
	    gl.glDepthFunc(GL.GL_LEQUAL);
	    gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
	    gl.glMatrixMode(GL.GL_MODELVIEW);
	    gl.glEnable(GL.GL_COLOR_MATERIAL);
	    gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE);
		gl.glEnable(GL.GL_LIGHTING);
		gl.glDepthFunc(GL.GL_LEQUAL);

	    
	    
	    gl.glLoadIdentity();	   
	    color = 1.0f;

	    for (GraphicalObject gr : GlobalObjects.getGraphicals()){
	    	gr.initialize(gl);
	    }

	    
	    tl = new TextLayer(drawable.getWidth()*9/10, drawable.getHeight()/20);
		tl.print(mission , 0f ,(float)fontsize, font, c);
		text = tl.getTexture(gl);

	    
	}

	float color;

	
	//@Override
	public void display(GLAutoDrawable drawable)
	{
	    GL gl = drawable.getGL();
	    gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
	    
	    double width = drawable.getWidth();
	    double height = drawable.getHeight();
	  
	    if (showMenu){
	    	
	    	if (showIntro){
	    		drawTextureRectangle( drawable, gl, intro, 0, 0, width, height);	    
	    	}else{
	    		
	    		drawTextureRectangle( drawable, gl, menu, 0, 0, width, height);
	    	}
	    		
	    	
	    }else{
	    	if (!Game.ended()){
	    		Universe.getGrUniverse().render(gl);
	    	
	    		//draw lives
	    		drawTextureRectangle( drawable, gl, getLivesTexture(),
	    								0, 0, width/8, height/20);
	    		
	    		String m = game.getCurrentMission(); 
	    		if (!m.equals(mission)){
	    			mission = m;
	    			tl.flushText(gl);
	    			tl.print(mission , 0f ,(float)fontsize, font, c);
	    			text = tl.getTexture(gl);
	    		}
	    		//write mission
	    		drawTextureRectangle( drawable, gl, text, width/8, 0, width*7/8, height/20);
	    		//draw weapon
	    		drawTextureRectangle( drawable, gl, getWeaponTexture(), width*11/12, height*9/10, width/12, height/10);
	    		
	    	}else{
	    		if (game.avatarWon()){
	    			drawTextureRectangle( drawable, gl, lastScreen, 0, 0, width, height);
	    		}else{
	    			showGameOver = true;
	    			drawTextureRectangle( drawable, gl, gameOver, 0, 0, width, height);
	    		}
	    	}
	    }
	    
	}

	private Texture getWeaponTexture( ) 
	{
		int weapon = game.getAvatar().getWeapon();
		switch(weapon){
		case 1:
			return weapon1;
		case 2:
			return weapon2;
		}
		return null;
		
	}

	private Texture getLivesTexture( ) 
	{
			int lives = game.getAvatar().getLives();
			switch(lives){
			case 0:
				return empty;
			case 1:
				return lives1;
			case 2:
				return  lives2;
			case 3:
				return lives3;
			case 4:
				return lives4;
			case 5:
				return  lives5;
			}
			return null;
	}
	
	//@Override
	public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
	{
	    GL gl = drawable.getGL();
		Universe.getCamera().paint(gl, width, height);
	}
	
	
	//@Override
	public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2) {
		// should remain empty
	}

	public static class Painter implements ActionListener {
		
	    private Game game;
		private GLCanvas canvas;

		public Painter(GLCanvas canvas, Game game){
	    	this.game = game;
	    	this.canvas = canvas;
	    }
		public void actionPerformed(ActionEvent evt) {
			synchronized (GlobalObjects.synchronizer) {
				game.actionPerformed(evt);
				canvas.repaint();
				
			}
		}
	 }

	
	public class TextLayer
	{
		BufferedImage textLayer;
		Graphics2D java2d;
		float left, right, top, bottom;
	    
		
        public TextLayer (int width, int height) // float left, float right,float top, float bottom)
        {
     
            textLayer = new BufferedImage (width, height,
                    BufferedImage.TYPE_3BYTE_BGR);
            java2d = (Graphics2D) textLayer.getGraphics ();
            }
        
        public void print (String output, float x, float y, Font font, Color color)
        {
            java2d.setColor (color);
            java2d.setFont (font);
            java2d.drawString (output, x, y);
        }
        
        
        public Texture getTexture(GL gl){
            return TextureIO.newTexture (textLayer, false);
        }
        
        public void flushText (GL gl){
        	java2d.setColor (new Color (0, 0, 0, 0));
        	java2d.clearRect (0, 0, textLayer.getWidth (), textLayer.getHeight ());
        }
        
	}
	
	
	/*
	 * -----------
	 * |         |
	 * x0,y0------
	 * 	
	 */
	private void drawTextureRectangle( GLAutoDrawable drawable, GL gl, Texture texture,
							 double x0, double y0, double width, double height) {
		try
		{		
			gl.glEnable(GL.GL_TEXTURE_2D);
			texture.bind();
			gl.glMatrixMode(GL.GL_PROJECTION);
			gl.glPushMatrix();
			gl.glLoadIdentity();
			gl.glOrtho(0, drawable.getWidth(),0, drawable.getHeight(), 0, 1);
			gl.glDisable(GL.GL_LIGHTING);
			
			gl.glBegin(GL.GL_QUADS);
			gl.glColor3f(1, 1, 1);
			gl.glTexCoord2f(0, 1);
			gl.glVertex2d(x0, y0);
			gl.glTexCoord2f(1, 1);
			gl.glVertex2d(x0+width, y0);
			gl.glTexCoord2f(1, 0);
			gl.glVertex2d(x0+width, y0+height);
			gl.glTexCoord2f(0, 0);
			gl.glVertex2d(x0, y0+height);
			gl.glEnd();
			gl.glFlush();
			
			gl.glDisable(GL.GL_TEXTURE_2D);
			gl.glMatrixMode(GL.GL_MODELVIEW);
			gl.glPopMatrix();
			gl.glEnable(GL.GL_LIGHTING);
			
		}
		
		catch (Exception e)
		{
			System.out.println("ERROR");
			e.printStackTrace();
		}
	}
	
	

}
